# -*- coding: utf-8 -*-
import json

from pptx import Presentation
import os
import wave
import comtypes.client
from moviepy.editor import ImageClip, concatenate_videoclips, AudioFileClip
from os.path import join, splitext
from os import listdir, remove
from shutil import rmtree
import requests
from re import findall
from datetime import datetime
from pydub import AudioSegment
from os import path, walk
import pythoncom
from requests_toolbelt.multipart.encoder import MultipartEncoder
from moviepy.editor import *
from moviepy.video.tools.subtitles import SubtitlesClip
import config.url_manager as UrlConfig


# def Audio_Set(ppt_path, texts, text_type, model_name, time):
#     final_video_path = os.path.join(os.getcwd(), 'data/tts_video', f'video_{datetime.now().strftime("%Y%m%d%H%M%S")}')
#     video_path = final_video_path + ".mp4"
#     audio_path = os.path.join(os.getcwd(), "merged_audio.wav")
#     texts, durations, audio_folder = ObtainPptNoteAndDuration(texts, text_type, model_name, time)  # 这里的time是停顿时间
#     video(ppt_path, final_video_path, texts, durations, audio_folder)
#     return video_path, audio_path, video_path


# 从ppt路径获取Presentation对象
def ObtainPptNoteAndDuration(texts, text_type, model_name, time):
    # 在/data/tts_audio文件夹中新创建一个名称中带有时间的音频文件夹
    audio_folder = os.path.join(os.getcwd(), '/data/tmp_audio', f'audio_{datetime.now().strftime("%Y%m%d%H%M%S")}')
    if not os.path.exists(audio_folder):
        os.makedirs(audio_folder)

    durations = []  #
    for index, text in enumerate(texts, start=1):
    # for index, text in texts:
        wav_path = os.path.join(audio_folder, f'text_{index}.wav')
        if text != '':
            tts(text, text_type, model_name, time, wav_path)
            # 获取音频时长并添加至列表中
            duration = get_audio_duration(wav_path)
            durations.append(duration)
        else:
            durations.append(3)  # 如果没有备注，设定音频时长为3s
            BlankAudio(3, wav_path)  # 如果没有备注，生成空白音频
    return durations, audio_folder


# 提取ppt备注
def GetTextByPPT(ppt_path):
    obj = Presentation(ppt_path)  # 得到路径下的ppt文件对象
    texts = []  # 定义存储备注的列表
    for index, slide in enumerate(obj.slides, start=1):
        text = slide.notes_slide.notes_text_frame.text  # 提取备注
        # if text != '':  # 备注非空
        texts.append(text)  # 将备注添加至列表中
    return texts


def BlankAudio(time, file_path):
    if time == 0:
        return
    duration = AudioSegment.silent(duration=time * 1000)
    duration.export(file_path, format="wav")


# 获取音频时长
def get_audio_duration(wav_path):
    # 使用适当的库获取音频文件的时长
    # 这里假设我们使用了wave库
    with wave.open(wav_path, 'r') as f:
        frames = f.getnframes()
        rate = f.getframerate()
        duration = frames / float(rate)
        return duration


# 将幻灯片转换为图片
def imgGenerator(ppt_fn, pictures_dir):
    pythoncom.CoInitialize()
    powerpoint = comtypes.client.CreateObject("PowerPoint.Application")
    powerpoint.Visible = True
    ppt = powerpoint.Presentations.Open(ppt_fn)
    ppt.SaveAs(pictures_dir + '.jpg', 17)
    ppt.Close()


# 生成视频
def video(ppt_fn, final_video_path, pinyins, time, audio_folder, merged_audio):
    pictures_dir = os.path.join(os.getcwd(), 'data', 'pics')
    # 要转换的ppt文件
    # 临时存放拆分后的幻灯片的文件夹，新建存放每页ppt截图的文件夹
    # pictures_dir = splitext(ppt_fn)[0] + '_pictures'  # 等号右边第一个是文件名(去除扩展名)

    # 把ppt转换为图片，每个幻灯片一个图片文件
    imgGenerator(ppt_fn, pictures_dir)

    # 对图片按幻灯片编号进行排序
    pictures = [join(pictures_dir, fn)
                for fn in listdir(pictures_dir)
                if fn.endswith('.JPG') or fn.endswith('.jpg')]  # 大小写虽然是一样的，但还是会区分
    pictures.sort(key=lambda fn: int(findall(r'\d+', fn)[-1]))  # 排序

    # 连接多个图片
    image = []
    i = 0
    for pic in pictures:
        if i < len(time):
            image.append(ImageClip(pic, duration=time[i]))
            i = i + 1
    result_video = concatenate_videoclips(image)  # 生成图片序列的视频，在这里加进字幕，通过time列表确定时间

    # 设置背景音乐
    MergeAudio(audio_folder, merged_audio, len(time), [], [])
    # wav_path = os.path.join(os.getcwd(), 'merged_audio.wav')
    wav_clip = AudioFileClip(merged_audio)
    result_video = result_video.set_audio(wav_clip)

    # 加字幕操作
    # output_file = "output.srt"
    # texts = GetTextByPPT(ppt_fn)
    # generate_srt_file(texts, time, output_file)
    # with open(output_file, 'r', encoding='utf-8') as f:
    #     content = f.read()
    #     with open(output_file, 'w', encoding='gbk') as gbk_file:
    #         gbk_file.write(content)
    # generator = lambda txt: TextClip(txt, font='华文宋体', fontsize=25, color='black')
    #
    # if len(texts) == 1:
    #     subtitles_data = [((0, time[0]), texts[0])]
    #     subtitles = SubtitlesClip(subtitles_data, generator)
    # else:
    #     subtitles = SubtitlesClip("output.srt", generator)
    #
    # subtitles = subtitles.set_position(('center', 'bottom'))
    # total_duration = sum(time)
    # subtitles.duration = total_duration
    # # 将字幕添加到视频中
    # video_with_subtitles = CompositeVideoClip([result_video, subtitles])
    video_with_subtitles = CompositeVideoClip([result_video])
    # os.remove(output_file)  # 删除字幕文件

    try:
        video_with_subtitles.write_videofile(final_video_path, fps=24,
                                             codec='libx264')  # 保存mp4视频，帧率24，指定编码为libx264
    except IOError as e:
        print(f"IOError: {e}")
    except Exception as e:
        print(f"Unexpected error: {e}")

    # 删除临时生成的文件夹
    DeleteAudio(audio_folder)
    rmtree(pictures_dir)


def generate_srt_file(texts, durations, output_file):
    with open(output_file, 'w', encoding='utf-8') as f:
        for i, (text, duration) in enumerate(zip(texts, durations), start=1):
            start_time = format_time(sum(durations[:i - 1]))
            end_time = format_time(sum(durations[:i]))

            if text == "\n":
                continue
            f.write(f"{i}\n")
            f.write(f"{start_time} --> {end_time}\n")
            text = text.strip("\n")
            f.write(f"{text}\n\n")


def format_time(seconds):
    hours, remainder = divmod(seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    milliseconds = int((seconds - int(seconds)) * 1000)
    return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d},{milliseconds:03d}"


# TTS参数
parameter1 = {
    "text": "",
    "speaker": "",
    "time": None,
    "sentence_time": 0,
    "segment_time": 0
}


# TTS函数
def tts(text, text_type, model_name, time, wav_path):
    url = UrlConfig.URL_TTS
    parameter1["text"] = text
    parameter1["type"] = text_type
    parameter1["speaker"] = model_name
    parameter1["time"] = time
    response = requests.post(url, data=parameter1, timeout=500)

    if response.status_code == 200:
        # wav_path: 本地 *.wav 路径
        with open(wav_path, 'wb') as f:
            f.write(response.content)


# 文本转拼音
def pretxt(text):
    url = UrlConfig.URL_PRETXT
    payload = {"text": text}
    res = requests.post(url, data=payload)
    print("res.content: ", res.content)
    data = json.loads(res.content)
    return data["text"], data["pinyin"]


def MergeAudio(folder, target_file, file_num, zero, exist):
    total = AudioSegment.empty()
    for i in range(file_num):
        if i in zero:
            continue
        piece = AudioSegment.from_wav(path.join(folder, "text_%s.wav" % (i + 1)))
        total = total + piece
    total.export(target_file, format="wav")


# 删除音频片段
def DeleteAudio(folder):
    for _, _, files in walk(folder):
        for file in files:
            if file.split('.')[-1] == 'wav' and len(file.split('.')[0]) <= 5:
                remove(path.join(folder, file))


# 模型训练
def train(speaker, zip_file_path):
    url = UrlConfig.URL_TRAIN
    zip_file_name = os.path.basename(zip_file_path)  # 获取zip文件的完整文件名，包括扩展名
    upload_file = (zip_file_name, open(zip_file_path, 'rb'), "application/zip")
    payload = MultipartEncoder(fields={"speaker": speaker, "file": upload_file})
    print(zip_file_name)
    requests.post(url, data=payload, headers={"Content-Type": payload.content_type})


# 查询训练进度
def train_info(speaker):
    url = UrlConfig.URL_TRAININFO
    payload = {"speaker": speaker}
    res = requests.get(url, data=payload)
    data = json.loads(res.content)
    return data["state"]


# 查询模型（音色）列表
def get_speakers():
    url = UrlConfig.URL_SPEAKERS
    res = requests.get(url)
    return json.loads(res.content)


# 删除模型
def delete_speaker(speaker):
    url = UrlConfig.URL_DELETE
    payload = {"speaker": speaker}
    requests.delete(url, data=payload)


def speed_adjust(speed, past_path):
    file_name = os.path.basename(past_path)  # 提取文件名，包括扩展名部分
    file_name_without_extension = os.path.splitext(file_name)[0]  # 去掉扩展名
    new_file_name = file_name_without_extension + "_speed_%s" % (speed)
    new_path = os.path.join('../aigc_vue/src/views/chat/video', 'tts_video', new_file_name) + ".mp4"
    new_audio_path = os.path.join(os.getcwd(), 'data', 'tts_audio', new_file_name) + ".wav"
    VideoFileClip('../aigc_vue/src/views/chat' + past_path).speedx(speed).write_videofile(new_path)
    my_clip = VideoFileClip(new_path)
    audio_clip = my_clip.audio
    audio_clip.write_audiofile(new_audio_path)
    return new_path, new_audio_path, new_file_name


# 试运行
if __name__ == "__main__":
    ppt_path = "E:\\sadtalker\\ppt2video\\resources\\思政课展示 (3).pptx"  # PPT文件路径
    final_video_path = os.path.join(os.getcwd(), 'results',
                                    f'video_{datetime.now().strftime("%Y%m%d%H%M%S")}')  # 最终视频路径
    duration = []  # 音频时长列表

    texts, durations, audio_folder = ObtainPptNoteAndDuration(ppt_path, "Jingci", 0.1)  # 从这里可以得到备注列表
    video(ppt_path, final_video_path, texts, durations, audio_folder)
